﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Threading;
using MIC_LOGIC;
using MIC_GUI.Model;
using MIC_GUI.ViewModel;

namespace MIC_GUI
{
	public partial class MainWindow
    {

        #region members
        private ILogicFacade _logic;
        private SerialDataConverter _data;
        private List<SerialDataValue> _dataModels;
        private Dispatcher _dispatcher;
        
        private bool _logEnable;
        #endregion

        #region delegates
        delegate void delegateForUIInvoke();
        #endregion

        public MainWindow()
		{
			this.InitializeComponent();
            
            _logEnable = false;

            _dispatcher = Dispatcher.CurrentDispatcher;
            
            this.Closed += new EventHandler(MainWindow_Closed);

            CommStudio.Connections.SerialOptions connOptions = new CommStudio.Connections.SerialOptions();
            connOptions.PortName = MIC_GUI.Properties.Settings.Default.ComPort;
            connOptions.BaudRate = MIC_GUI.Properties.Settings.Default.BaudRate;
            connOptions.Parity = CommStudio.Connections.Parity.None;
            connOptions.DataBits = 8;
            connOptions.StopBits = CommStudio.Connections.CommStopBits.One;

            _logic = new LogicFacade();
            _logic.ConnectionOptions = connOptions;

            _data = new SerialDataConverter(_logic);


            _logic.LoggerSettings(            
                MIC_GUI.Properties.Settings.Default.CHANNEL_0,
                MIC_GUI.Properties.Settings.Default.CHANNEL_1,
                MIC_GUI.Properties.Settings.Default.CHANNEL_2
            );                           
            
            
            //Inits dataModels to manipulate and display on the UI
            _dataModels = new List<SerialDataValue>();    
            _dataModels.Add(new SerialDataValue());
            _dataModels.Add(new SerialDataValue());
            _dataModels.Add(new SerialDataValue());
        
            _logic.OnErrorMessage += new StringDelegate(_tbInfo_eventHandler);
            _logic.OnInfoMessage += new StringDelegate(_tbInfo_eventHandler);
            _data.OnError += new StringDelegate(_tbInfo_eventHandler);
            _logic.OnChecksumErrorChanged += new IntegerDelegate(_logic_OnChecksumErrorChanged);

            _data.OnDataValuesConverted += new EventHandler(_data_OnDataValuesConverted);

            //Add models to context
            stream1.DataValues = _dataModels[0].DataValues;
            stream1.GraphTitle = MIC_GUI.Properties.Settings.Default.CHANNEL_0;

            stream2.DataValues = _dataModels[1].DataValues;
            stream2.GraphTitle = MIC_GUI.Properties.Settings.Default.CHANNEL_1;

            stream3.DataValues = _dataModels[2].DataValues;
            stream3.GraphTitle = MIC_GUI.Properties.Settings.Default.CHANNEL_2;

            btnDataStreamSettings.Click += new RoutedEventHandler(btnDataStreamSettings_Click);
            btnConnectSerialStream.Click += new RoutedEventHandler(btnConnectSerialStream_Click);
            btnConnectSimulation.Click += new RoutedEventHandler(btnConnectSimulation_Click);
            btnLogging.Click += new RoutedEventHandler(btnLogging_Click);

            this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
           
		}

        void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            _logic.CloseSerial();
        }

        void btnLogging_Click(object sender, RoutedEventArgs e)
        {
            if (!_logEnable)
            {
                string filename = 
                    Environment.CurrentDirectory + @"\LogFiles\" + 
                    "Angle log " + DateTime.Now.ToString().Replace(':', '_') + ".xls";

                if (_logic.StartLogger(filename))
                {
                    _logEnable = true;
                    btnLogging.Content = "Stop logging";
                    AddTextToInfo("Created new log: " + filename); 
                }
            }
            else
            {
                if (_logic.StopLogger())
                {
                    _logEnable = false;
                    btnLogging.Content = "Start logging";
                    AddTextToInfo("Logging stopped");
                }
            }
        }

        

        void btnConnectSimulation_Click(object sender, RoutedEventArgs e)
        {
            if (btnConnectSimulation.Content.ToString().CompareTo("Start Simulation") == 0)
            {
                _logic.StartDataSimulation();
                btnConnectSimulation.Content = "Stop Simulation";
                btnConnectSerialStream.IsEnabled = false;
                btnDataStreamSettings.IsEnabled = false;
            }
            else
            {
                _logic.StopDataSimulation();
                btnConnectSimulation.Content = "Start Simulation";
                btnConnectSerialStream.IsEnabled = true;
                btnDataStreamSettings.IsEnabled = true;
            }
        }

        void btnConnectSerialStream_Click(object sender, RoutedEventArgs e)
        {
            if (btnConnectSerialStream.Content.ToString().CompareTo("Connect Serial")==0)
            {
                _logic.StartSerialStream();
                btnConnectSerialStream.Content = "Disconnect Serial";
                btnConnectSimulation.IsEnabled = false;
                btnDataStreamSettings.IsEnabled = false;
            }
            else
            {
                _logic.StopSerialStream();
                btnConnectSerialStream.Content = "Connect Serial";
                btnConnectSimulation.IsEnabled = true;
                btnDataStreamSettings.IsEnabled = true;
            }
        }

        void btnDataStreamSettings_Click(object sender, RoutedEventArgs e)
        {
            SettingsPopup settings = new SettingsPopup();
            settings.SerialCofiguration = _logic.ConnectionOptions;
            settings.LogConfiguration = _logic.LogConfiguration;
            settings.ShowDialog();

            if (settings.IsOKPressed)
            {
                AddTextToInfo("OK pressed");

                _logic.ConnectionOptions = settings.SerialCofiguration;
                _logic.LogConfiguration = settings.LogConfiguration;

                MIC_GUI.Properties.Settings.Default.ComPort = settings.SerialCofiguration.PortName;
                MIC_GUI.Properties.Settings.Default.BaudRate = settings.SerialCofiguration.BaudRate;

                MIC_GUI.Properties.Settings.Default.Save();

            }
            else
            {
                AddTextToInfo("Cancel pressed");
            }
        }

        void _logic_OnChecksumErrorChanged(int value)
        {
 
            delegateForUIInvoke UIupdate = delegate
            {
                lblChecksumErrors.Content = "Discarded packages: " + value.ToString();
            };
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, UIupdate);
           
        }

        void MainWindow_Closed(object sender, EventArgs e)
        {
        }

        void _tbInfo_eventHandler(string msg)
        {
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new StringDelegate(AddTextToInfo), msg);
            
        }
        
        void AddTextToInfo(string txt)
        {
            delegateForUIInvoke UIupdate = delegate
            {
                if (tbInfo.LineCount > 50)
                {
                    tbInfo.Text = tbInfo.Text.Remove(0, tbInfo.Text.IndexOf('\n', 2));
                }

                tbInfo.AppendText(txt + "\n");
                tbInfo.ScrollToEnd();
            };
            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, UIupdate);
        }

        double _lastAngle = 0;
        DateTime _lastTime = DateTime.Now;

        void _data_OnDataValuesConverted(object sender, EventArgs e)
        {
            _dataModels[0].Add(_data.AccelerometerAngle);
            _dataModels[1].Add(_data.GyroAnglePrSec);
            _dataModels[2].Add(_data.ApproximatedAngle);

            _lastAngle = _data.ApproximatedAngle;
            TimeSpan dt = DateTime.Now - _lastTime;

            double gyroAngle = _lastAngle + (_data.GyroAnglePrSec * (dt.Milliseconds / 1000));
            _lastTime = DateTime.Now;

            delegateForUIInvoke UIupdate = delegate
            {
                AngleTransform.Angle = _data.ApproximatedAngle;
                AccelAngleTransform.Angle = _data.AccelerometerAngle;
                GyroAngleTransform.Angle = gyroAngle;
                lblTiltRate.Content = "" + (_data.ApproximatedAngle) + "°";

            };



            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, UIupdate);
        }
	}
}